#include "SponzaScene.h"

#include "StaticModel.h"
#include "SkyDome.h"

SponzaScene::SponzaScene()
{
	//Init pointers to NULL 
	sponza = 0;
	skyDome = 0;
}

SponzaScene::~SponzaScene()
{}

void SponzaScene::OpenScene()
{
	//Seed random number generator to 0 - thus, each time we run the game, the 
	//point/spot lights will be located and coloured exactly the same. 
	srand(0);

	//Disable MSAA
	sharedGraphicsInterface->Set4XMSAA(false);

	//Init camera position / frustum properties.
	camera->SetPosition(XMFLOAT3(0.0f, 2.0f, -5.0f));
	OnResize();

	//Set scene lighting. Randomly place lights in a gridl.
	TileBasedLight* lightArr = new TileBasedLight[NUM_LIGHTS_SPONZA];
	//Loop through lights and set properties.
	for (UINT i = 0; i < NUM_LIGHTS_SPONZA; i++)
	{
		//No colour output. 
		XMFLOAT4 null = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);
		//Random diffuse and spec colour.
		XMFLOAT4 diffCol = XMFLOAT4(MathHelper::RandF(), MathHelper::RandF(), 
			MathHelper::RandF(), 1.0f);
		//Ambient term
		XMFLOAT4 diffColDiv = XMFLOAT4(diffCol.x/5.0f, diffCol.y/5.0f, 
			diffCol.z/5.0f, 1.0f);
		//Random location.
		XMFLOAT3 randLoc = XMFLOAT3(MathHelper::RandF(-27.0f, 30.0f),
			MathHelper::RandF(0.0f, 70.0f), MathHelper::RandF(-70.0f, 80.0));
		//Randon range.
		float randRange = MathHelper::RandF(5.0f, 15.0f);
		//Create point lights. 
		lightArr[i].InitPointLight(diffColDiv, diffCol, diffCol, 
			randLoc, randRange);
	}

	//Set scene lighting - creating our required buffers - we want the option
	//to visualise our lights, so set the required bool to true.
	sharedGraphicsInterface->SetSceneLights(lightArr, NUM_LIGHTS_SPONZA, true);
	//Delete dynamically allocated light array.
	delete []lightArr;

	//Set Directional light. 
	dLight.Ambient = XMFLOAT4(0.06f, 0.06f, 0.06f, 1.0f);
	dLight.Diffuse = XMFLOAT4(0.6f, 0.6f, 0.6f, 1.0f);
	dLight.Specular = XMFLOAT4(0.3f, 0.3f, 0.3f, 64.0f);
	dLight.Direction = XMFLOAT3(0.7f, -0.3f, -0.7f);
	sharedGraphicsInterface->SetDirectionalLights(&dLight, 1, 0);
	shouldUseDLight = true;

	//Initial Scene State is to draw scene as usual.
	sceneState = SCENE_STATE_DRAW_SCENE;
	//Lights initially to be rendered
	shouldRenderLights = true;
	sharedGraphicsInterface->SetCurrentSkyDome(NULL);

	//Load sponza scene
	sponza = new StaticModel();
	sponza->CreateModelThroughAssimp(sharedGraphicsInterface->GetDevice(), 
		std::string("SponzaCrytek/sponza.obj"), std::string("SponzaCrytek/"), true, true, true, 
		false, false);
	sponza->SetWorldScale(XMFLOAT3(0.05f, 0.05f, 0.05f));
	sponza->SetWorldRotation(XMFLOAT3(0.0f, MathHelper::ToRadians(90.0f), 0.0f));
	sponza->SetIsShadowCaster(false); //Doesnt cast shadows.

	//Set skydome.
	skyDome = new SkyDome(sharedGraphicsInterface->GetDevice(),
		L"Textures/grasscube1024.dds",
		camera);
	sharedGraphicsInterface->SetCurrentSkyDome(skyDome);
}

void SponzaScene::CloseScene()
{
	SafeDelete(sponza);
	SafeDelete(skyDome);
}

void SponzaScene::OnMouseDown(WPARAM btnState, int x, int y, UINT originalMessage)
{
	AbstractScene::OnMouseDown(btnState, x, y, originalMessage);
}

void SponzaScene::OnMouseUp(WPARAM btnState, int x, int y, UINT originalMessage)
{
	//Togle Dlight. 
	if (originalMessage == WM_RBUTTONUP)
		shouldUseDLight = !shouldUseDLight;
}

void SponzaScene::OnMouseMove(WPARAM btnState, int x, int y)
{
	AbstractScene::OnMouseMove(btnState, x, y);
}

void SponzaScene::OnResize()
{
	AbstractScene::OnResize();
}

void SponzaScene::UpdateWithDelta(float delta)
{
	AbstractScene::UpdateWithDelta(delta);

	//Decide what to render?
	if( GetAsyncKeyState('1') & 0x8000 )
		sceneState = SCENE_STATE_DRAW_SCENE; 
	if( GetAsyncKeyState('2') & 0x8000 )
		sceneState = SCENE_STATE_DRAW_Z_PRE_PASS_DEPTH_BUFFER; 
	if ( GetAsyncKeyState('3') & 0x8000 )
		sceneState = SCENE_STATE_DRAW_CS_MAX_Z_DEPTH_BUFFER;
	if ( GetAsyncKeyState('4') & 0x8000 )
		sceneState = SCENE_STATE_DRAW_CS_LLSEB_GREYSCALE;
	if ( GetAsyncKeyState('5') & 0x8000 )
		sceneState = SCENE_STATE_DRAW_CS_LLSEB_COLOUR;
	if ( GetAsyncKeyState('6') & 0x8000 )
		sceneState = SCENE_STATE_DRAW_CS_LLSEBT_GREYSCALE;
	if ( GetAsyncKeyState('7') & 0x8000 )
		sceneState = SCENE_STATE_DRAW_CS_LLSEBT_COLOUR;

	//Render the lights?
	if ( GetAsyncKeyState('G') & 0x8000 )
		shouldRenderLights = true;
	if ( GetAsyncKeyState('F') & 0x8000 )
		shouldRenderLights = false;

	//Upload Directional light to GraphicsInterface
	if (shouldUseDLight)
		sharedGraphicsInterface->SetDirectionalLights(&dLight, 1, 0);
	else
		sharedGraphicsInterface->SetDirectionalLights(NULL, 0, 0);
}

void SponzaScene::RenderScene()
{
	//
	//Start rendering - Clear backbuffer and depth stencil view.
	//
	sharedGraphicsInterface->StartFrame(
		reinterpret_cast<const float*>(&Colors::LightSteelBlue),
		camera);

	//
	//Add models to the batches. 
	//
	sharedGraphicsInterface->AddModelToBatch(sponza);

	//
	//Render to the scene.
	//
	sharedGraphicsInterface->Render(shouldRenderLights, false);


	//
	//Debug Rendering
	//
	//Draw depth buffer (filled from Z Pre Pass).
	if (sceneState == SCENE_STATE_DRAW_Z_PRE_PASS_DEPTH_BUFFER)
		sharedGraphicsInterface->DrawZPrePassFilledDepthBuffer();
	//Draw max tile depth texture.
	else if (sceneState == SCENE_STATE_DRAW_CS_MAX_Z_DEPTH_BUFFER)
		sharedGraphicsInterface->DrawTileMaxZBuffer(); 
	else if (sceneState == SCENE_STATE_DRAW_CS_LLSEB_GREYSCALE)
		sharedGraphicsInterface->DrawLightListStartEndBufferGreyscale();
	else if (sceneState == SCENE_STATE_DRAW_CS_LLSEB_COLOUR)
		sharedGraphicsInterface->DrawLightListStartEndBufferColour();
	else if (sceneState == SCENE_STATE_DRAW_CS_LLSEBT_GREYSCALE)
		sharedGraphicsInterface->DrawLightListStartEndBufferTransparantGreyscale();
	else if (sceneState == SCENE_STATE_DRAW_CS_LLSEBT_COLOUR)
		sharedGraphicsInterface->DrawLightListStartEndBufferTransparantColour();

	//Present the backbuffer (if in full screen, present with vsync on)
	bool fsState = sharedGraphicsInterface->IsInFullScreenMode();
	sharedGraphicsInterface->EndFrame(fsState);
}